/*
Source Code License Agreement
Copyright (c) 2007, Matthew D. Wright. All rights reserved.

Matthew D. Wright grants to you a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable copyright license, to reproduce,
prepare derivative works of, publicly display, publicly perform, and
distribute this source code and such derivative works in source or
object code form without any attribution requirements.

The name "Matthew D. Wright" must not be used to endorse or promote 
products derived from the source code without prior written permission.

You agree to indemnify, hold harmless and defend Matthew D. Wright from 
and against any loss, damage, claims or lawsuits, including attorney's fees 
that arise or result from your use or distribution of the source code.

THIS SOURCE CODE IS PROVIDED "AS IS" AND "WITH ALL FAULTS", WITHOUT
ANY TECHNICAL SUPPORT OR ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ALSO, THERE IS NO WARRANTY OF
NON-INFRINGEMENT, TITLE OR QUIET ENJOYMENT. IN NO EVENT SHALL MACROMEDIA
OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOURCE CODE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package net.nobien.webapis.google.accounts
{
	import flash.events.Event;
	import flash.events.HTTPStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.URLRequestHeader;
	import flash.net.URLRequestMethod;
	import flash.net.URLVariables;
	
	import net.nobien.webapis.google.events.AccountsEvent;
	import net.nobien.webapis.google.utils.AccountsHelper;
	
	/**
	 * The ClientLogin class abstracts Google's ClientLogin Interface.
	 * More information about the ClientLogin Interface can be found at 
	 * http://code.google.com/apis/accounts/AuthForInstalledApps.html
	 */
	public class ClientLogin 
	{
		/**
		 * The endpoint where Google accounts are authenticated.
		 */
		public static const AUTH_END_POINT:String = "https://www.google.com/accounts/ClientLogin";
		
		/**
		 * Parameter string used for authenticating a Google account.
		 */
		public static const GOOGLE:String = "GOOGLE";
		
		/**
		 * Parameter string used for authenticating a hosted account.
		 */
		public static const HOSTED:String = "HOSTED";
		
		/**
		 * Parameter string used for when you are unsure which account 
		 * type to authenticate.
		 */
		public static const HOSTED_OR_GOOGLE:String = "HOSTED_OR_GOOGLE";
		
		/**
		 * HTTP Success code.
		 */
		private static const HTTP_OK:int = 200;
		
		/**
		 * Holder for the requests HTTP status code.
		 */
		private var _httpStatus:int;
		
		/**
		 * Private reference to AccountsService object.
		 */
		private var _service:AccountsService;
		
		
		/**
		 * Constructs a new ClientLogin object.
		 * @param service AccountsService - The AccountsService object the 
		 *     ClientLogin object is associated with.
		 */
		public function ClientLogin( service:AccountsService ) 
		{
			_service = service;
		}
		
		/* Generic Event Handlers */
		private function handleLoaderProgress( event:ProgressEvent ):void
        {
        	_service.dispatchEvent( event );
        }
        
        private function handleLoaderHTTPStatus( event:HTTPStatusEvent ):void
		{
			_httpStatus = event.status;
			_service.dispatchEvent( event );
		}
		
		private function handleLoaderIOError( event:IOErrorEvent ):void
		{
			_service.dispatchEvent( event );
		}
		
		private function handleLoaderSecurityError( event:SecurityErrorEvent ):void
		{
			_service.dispatchEvent( event );
		}
		
		/**
		 * Capture the result of the <code>authenticate</code> method call and dispatch the 
		 * event according to the response.
		 * @param event The complete event generated by the URLLoader
		 */
		private function handleAuthenticationResponse( event:Event ):void
        {
        	var response:String = String( event.target.data );
        	var accEvent:AccountsEvent = null;
        	
        	if( _httpStatus == HTTP_OK )
			{
				accEvent = new AccountsEvent( AccountsEvent.AUTH_GET_TOKEN );
				
				var authResult:AuthResult = AccountsHelper.parseAuthResponse( response );
				
				_service.authToken = authResult.auth;
				_service.authHeader = new URLRequestHeader( "Authorization", "GoogleLogin auth=" + _service.authToken );
				
				accEvent.data = authResult;
			}
			else
            {
				accEvent = new AccountsEvent( AccountsEvent.AUTH_FAILURE );
				var authError:AuthError = AccountsHelper.parseAuthError( response );
				
				accEvent.data = authError;
            }
            
			_service.dispatchEvent( accEvent );
        }
		
		/**
		 * Attempts to authenticate a user for a Google service.
		 * 
		 * @param username User's full email address
		 * @param password User's password
		 * @param service Name of the Google service for which 
		 *     authorization is requested
		 * @param source Short string identifying the application 
		 * @param accountType Type of account to be authenticated
		 * @see http://code.google.com/apis/accounts/AuthForInstalledApps.html#Request
		 */
		public function authenticate( username:String, password:String, service:String, source:String, accountType:String = "" ):void
		{
			var vars:URLVariables = new URLVariables();
			vars.accountType = accountType;
			vars.Email = username;
			vars.Passwd = password;
			vars.service = service;
			vars.source = source;
			
			var request:URLRequest = new URLRequest();
			request.method = URLRequestMethod.POST;
			request.url = AUTH_END_POINT;
			request.data = vars;
			
			var loader:URLLoader = new URLLoader();
			loader.addEventListener( ProgressEvent.PROGRESS, handleLoaderProgress );
            loader.addEventListener( HTTPStatusEvent.HTTP_STATUS, handleLoaderHTTPStatus );
            loader.addEventListener( SecurityErrorEvent.SECURITY_ERROR, handleLoaderSecurityError );
            loader.addEventListener( IOErrorEvent.IO_ERROR, handleLoaderIOError );
			loader.addEventListener( Event.COMPLETE, handleAuthenticationResponse );
			loader.load( request );
		}
		
	}
	
}
